module regs (
    input clk,
    input rst,
    input [3:0] key_row,
    input [1:0] ra,
    input wr,
    input rd,
    input [1:0] m,
    input [1:0] key_sel,
    input [3:0] remain,
    input [1:0] btn,
    input [7:0] res,
    input is_write,
    output [3:0] key_col,
    output [7:0] seg,
    output [2:0] sel,
    output reg [2:0] s,
    output reg [7:0] x,
    output reg [7:0] y
);

  wire [3:0] val;
  wire is_pressed;

  key u_key (
      clk,
      rst,
      key_row,
      key_col,
      val,
      is_pressed
  );

  reg [31:0] data;
  reg [ 7:0] en;

  display u_display (
      clk,
      rst,
      data,
      en,
      seg,
      sel
  );

  reg [7:0] pc;
  reg [7:0] r[0:3];

  reg [16:0] cnt;
  localparam CNT_MAX = 17'd99_999;

  reg page;

  always @(negedge clk or negedge rst) begin
    if (!rst) begin
      page <= 1'b0;
    end else if (!btn[0]) begin
      page <= 1'b0;
    end else if (!btn[1]) begin
      page <= 1'b1;
    end else begin
      page <= page;
    end
  end

  wire [2:0] x_sel;
  wire [2:0] y_sel;
  wire [2:0] res_sel;

  assign x_sel   = {m, remain[3]};
  assign y_sel   = remain[2:0];
  assign res_sel = {ra, wr};

  always @(*) begin
    s = {rd, key_sel[0], key_sel[1]};
  end

  reg is_up;
  reg is_down;

  always @(negedge clk or negedge rst) begin
    if (!rst) begin
      pc <= 8'd0;
      r[0] <= 8'd0;
      r[1] <= 8'd0;
      r[2] <= 8'd0;
      r[3] <= 8'd0;
      data <= 32'd0;
      en <= 8'b00000000;
      cnt <= 17'd0;
      x <= 8'd0;
      y <= 8'd0;
      is_up <= 1'b0;
      is_down <= 1'b0;
    end else if (!page) begin
      en <= 8'b11001100;
      data[23:16] <= pc;
      data[7:0] <= r[ra];
      case (m)
        2'b00: begin
          pc <= 8'd0;
          is_up <= 1'b0;
          is_down <= 1'b0;
        end
        2'b01: begin
          if (key_sel[0] && is_pressed) begin
            case (key_sel[1])
              1'b0: begin
                pc[7:4] <= val;
              end
              1'b1: begin
                pc[3:0] <= val;
              end
            endcase
          end
          is_up   <= 1'b0;
          is_down <= 1'b0;
        end
        2'b10: begin
          is_up   <= 1'b1;
          is_down <= 1'b0;
          if (cnt == CNT_MAX) begin
            cnt <= 17'd0;
            pc  <= pc + 1'b1;
          end else begin
            cnt <= cnt + 1'b1;
          end
        end
        2'b11: begin
          is_up   <= 1'b0;
          is_down <= 1'b1;
          if (cnt == CNT_MAX) begin
            cnt <= 17'd0;
            pc  <= pc - 1'b1;
          end else begin
            cnt <= cnt + 1'b1;
          end
        end
      endcase

      case ({
        wr, rd
      })
        2'b01: begin
          if (!key_sel[0] && is_pressed) begin
            case (key_sel[1])
              1'b0: begin
                r[ra][7:4] <= val;
              end
              1'b1: begin
                r[ra][3:0] <= val;
              end
            endcase
          end
        end
      endcase
    end else begin
      en <= 8'b11001111;
      data[31:24] <= x;
      data[23:16] <= y;
      data[7:0] <= res;

      case ({
        is_up, is_down
      })
        2'b01: begin
          if (cnt == CNT_MAX) begin
            cnt <= 17'd0;
            pc  <= pc - 1'b1;
          end else begin
            cnt <= cnt + 1'b1;
          end
        end
        2'b10: begin
          if (cnt == CNT_MAX) begin
            cnt <= 17'd0;
            pc  <= pc + 1'b1;
          end else begin
            cnt <= cnt + 1'b1;
          end
        end
      endcase

      if (x_sel[2]) begin
        x <= pc;
      end else begin
        x <= r[x_sel[1:0]];
      end

      if (y_sel[2]) begin
        y <= pc;
      end else begin
        y <= r[y_sel[1:0]];
      end

      if (!is_write) begin
        if (res_sel[2]) begin
          pc <= res;
        end else begin
          r[res_sel[1:0]] <= res;
        end
      end

    end
  end

endmodule
